//
// Created by ZLY on 2025/3/29.
//

#include "DemuxThread.h"


DemuxThread::DemuxThread(AVPacketQueue *audio_queue, AVPacketQueue *video_queue)
    : audio_queue_(audio_queue), video_queue_(video_queue) {
    av_log(NULL, AV_LOG_VERBOSE, "DemuxThread::Init()");
}

DemuxThread::~DemuxThread() {
    av_log(NULL, AV_LOG_VERBOSE, "DemuxThread::Destroy()");
    if (thread_ != nullptr) {
        Stop();
    }
}

int DemuxThread::Init(const char *url) {
    // std::cout<<"DemuxThread::url: "<<url<<std::endl;
    url_ = url;
    fmt_ctx_ = avformat_alloc_context();
    int ret = avformat_open_input(&fmt_ctx_, url, NULL, NULL);
    if (ret < 0) {
        av_strerror(ret, err2str, sizeof(err2str));
        av_log(NULL, AV_LOG_ERROR, "DemuxThread::Init() avformat_open_input ret:%s\n", err2str);
        return -1;
    }
    av_dump_format(fmt_ctx_, 0, url, 0);
    av_log(NULL, AV_LOG_VERBOSE, "DemuxThread::Init() end\n");
    audio_index_ = av_find_best_stream(fmt_ctx_, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0);
    video_index_ = av_find_best_stream(fmt_ctx_, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
    av_log(NULL,AV_LOG_VERBOSE, "DemuxThread::Init() audio_index:%d\n", audio_index_);
    av_log(NULL,AV_LOG_VERBOSE, "DemuxThread::Init() video_index:%d\n", video_index_);
    if (audio_index_ < 0 || video_index_ < 0) {
        av_log(NULL,AV_LOG_ERROR, "DemuxThread::Init() av_find_best_stream returned -1\n");
        return -1;
    }

    return 0;
}

int DemuxThread::Start() {
    thread_ = new std::thread(&DemuxThread::Run, this);
    if (!thread_) {
        av_log(NULL, AV_LOG_ERROR, "DemuxThread::Start() ERROR\n");
        return -1;
    }

    return 0;
}

int DemuxThread::Stop() {
    Thread::Stop();
    avformat_close_input(&fmt_ctx_);

    return 0;
}

void DemuxThread::Run() {

    av_log(NULL, AV_LOG_VERBOSE, "DemuxThread::Run() start\n");
    int ret = 0;
    AVPacket packet;
    int audio_count=0;
    int video_count=0;
    while (abort_ != 1) {
        if (audio_queue_->Size() > 10 || video_queue_->Size() > 10) {
            av_log(NULL, AV_LOG_VERBOSE, "DemuxThread::Stop() sleep\n");
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
            continue;
        }
        ret = av_read_frame(fmt_ctx_, &packet);
        if (ret < 0) {
            av_log(NULL, AV_LOG_ERROR, "DemuxThread::Run() ERROR\n");
            break;
        }
        if (packet.stream_index == audio_index_) {
            av_log(NULL, AV_LOG_VERBOSE, "DemuxThread::Run() video_queue size:%d\n", video_queue_->Size());
            audio_queue_->Push(&packet);
            if (++audio_count%100==0) {
                av_log(NULL, AV_LOG_INFO, "DemuxThread::Run() audio_count size:%d\n", audio_count);
            }
        } else if (packet.stream_index == video_index_) {
            av_log(NULL,AV_LOG_VERBOSE, "DemuxThread::Run() video_queue size:%d\n", video_queue_->Size());
            video_queue_->Push(&packet);
            if (++video_count%100==0) {
                av_log(NULL, AV_LOG_INFO, "DemuxThread::Run() video_count size:%d\n", video_count);
            }
        } else {
            av_packet_unref(&packet);
        }
    }
    av_log(NULL, AV_LOG_VERBOSE, "DemuxThread::Run() end\n");
}

AVCodecParameters *DemuxThread::AudioCodecParameters() {
    if (audio_index_ != -1) {
        return fmt_ctx_->streams[audio_index_]->codecpar;
    } else {
        return nullptr;
    }
}

AVCodecParameters *DemuxThread::VideoCodecParameters() {
    if (video_index_ != -1) {
        return fmt_ctx_->streams[video_index_]->codecpar;
    } else {
        return nullptr;
    }
}
